/*
 *
 *   Copyright (C) 2005 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include <string.h>
#include <urlglib/url_filter.h>

// UrlItem -----------------------------------------------------------

UrlItem* url_item_new (char* string, int len)
{
	UrlItem* uitem;

	if (len == -1)
		len = (string) ? strlen (string) : 0;

	uitem = g_malloc0 (sizeof (UrlItem) + len + 1);
	uitem->string = (char*)(uitem + 1);
	memcpy (uitem->string, string, len);
	uitem->reference_count = 1;

	return uitem;
}

void  url_item_ref (UrlItem* uitem)
{
	uitem->reference_count++;
}

void  url_item_unref (UrlItem* uitem)
{
	if (--uitem->reference_count == 0) {
		g_slist_foreach (uitem->related_list, (GFunc)url_item_unref, NULL);
		g_slist_free (uitem->related_list);
		g_message ("UrlItem freed");
	}
}

void  url_item_add_related (UrlItem* uitem, UrlItem* related_item)
{
	uitem->related_list = g_slist_prepend (uitem->related_list, related_item);
	url_item_ref (related_item);
}

void  url_item_pick_related_item (UrlItem* uitem)
{
	GSList* slist;
	UrlItem* related_item;

	for (slist=uitem->related_list; slist; slist=slist->next) {
		related_item = slist->data;
		related_item->picked_count++;
	}
}

// UrlItemList -------------------------------------------------------

void url_item_list_instance_init (UrlItemList* uilist)
{
//  uilist->finalize        = url_item_list_instance_finalize;
	uilist->added_signal    = NULL;
	uilist->item_list       = NULL;
	uilist->item_list_tail  = NULL;
	uilist->reference_count = 1;
}

void url_item_list_instance_finalize (UrlItemList* uilist)
{
	urlglib_signal_list_free (&uilist->added_signal);
	g_slist_foreach (uilist->item_list, (GFunc)url_item_unref, NULL);
	g_slist_free (uilist->item_list);
}

void url_item_list_ref (UrlItemList* uilist)
{
	uilist->reference_count++;
}

void url_item_list_unref (UrlItemList* uilist)
{
	if (--uilist->reference_count == 0)
		uilist->finalize (uilist);
}

void url_item_list_set_item_all (UrlItemList* uilist, gboolean mark, int picked_count)
{
	GSList* slist;
	UrlItem* uitem;

	for (slist=uilist->item_list; slist; slist=slist->next) {
		uitem = slist->data;
		uitem->mark = mark;
		uitem->picked_count = picked_count;
	}
}

void url_item_list_add (UrlItemList* uilist, UrlItem* uitem)
{
	GSList* tail = uilist->item_list_tail;

	tail = g_slist_append (tail, uitem);
	if (uilist->item_list == NULL) {
		uilist->item_list = tail;
		uilist->item_list_tail = tail;
	} else {
		uilist->item_list_tail = tail->next;
	}

	// emit signal
	url_item_list_item_added (uilist, uitem, tail);
}

// notification
void url_item_list_item_added (UrlItemList* uilist, UrlItem* uitem, GSList* slist)
{
	UrlglibSignal*  ug_signal;
	GSList** signal_list = &uilist->added_signal;

	URLGLIB_SIGNAL_EMIT_BEG (signal_list, ug_signal);
		((UrlItemListCallback)ug_signal->callback) (uilist, uitem, slist, ug_signal->data);
	URLGLIB_SIGNAL_EMIT_END ();

/*
	{                                  
		GList* __list_1;                           
		for (__list_1 = *signal_list; __list_1; __list_1=__list_1->next) {    
			ug_signal = (UrlglibSignal*)__list_1->data;
			((UrlItemListCallback)ug_signal->callback) (uilist, uitem, ug_signal->data);
		}
	}
*/
}

// UrlFilter ---------------------------------------------------------

void url_filter_finalize (UrlFilter* filter)
{
	g_slist_foreach (filter->class_list, (GFunc)url_item_list_unref, NULL);
	g_slist_free (filter->class_list);

	url_item_list_instance_finalize (URL_ITEM_LIST (filter));
	g_message ("UrlFilter free");
}

UrlFilter* url_filter_new ()
{
	UrlFilter*  filter = g_malloc0 (sizeof (UrlFilter));

	url_item_list_instance_init (URL_ITEM_LIST (filter));
	filter->finalize = (UrlItemListFinalizeFunc)url_filter_finalize;

	return filter;
}

void url_filter_add_class (UrlFilter* filter, UrlFilterClass* fclass)
{
	filter->class_list = g_slist_prepend (filter->class_list, fclass);
}

UrlFilterClass* url_filter_get_class (UrlFilter* filter, UrlFilterClassFunc func)
{
	GSList* slist;
	UrlFilterClass* fclass;

	for (slist=filter->class_list; slist; slist=slist->next) {
		fclass = slist->data;
		if (fclass->class_func == func)
			return fclass;
	}
	return NULL;
}

void url_filter_add_item (UrlFilter* filter, char* url, char* base_href)
{
	url_filter_add_item_len (filter, url, -1, base_href);
}

void url_filter_add_item_len (UrlFilter* filter, char* url, int url_len, char* base_href)
{
	GSList* slist;
	UrlItem* uitem;
	UrlFilterClass* fclass;
	GString* gstr_url = NULL;
	int   index;

	if (url==NULL || *url == 0)
		return;

	if (url_len == -1)
		url_len = strlen (url);

	if (base_href) {
		// merge base_href and url if need.
		for (index=0; index < url_len; index++) {
			if ( url[index] == ':')
				break;
		}
		if (index==url_len) {
			gstr_url = g_string_new (base_href);
			if (gstr_url->str [gstr_url->len-1] != '/')
				g_string_append_c (gstr_url, '/');
			g_string_append (gstr_url, url);
			url = gstr_url->str;
			url_len = gstr_url->len;
		}
	}

	url_info_part_len (&filter->url_info, url, url_len);
	uitem = url_item_new (url, url_len);
	url_item_list_add (URL_ITEM_LIST (filter), uitem);

	if (gstr_url)
		g_string_free (gstr_url, TRUE);

	for (slist=filter->class_list; slist; slist=slist->next) {
		fclass = slist->data;
		fclass->class_func (fclass, uitem, &filter->url_info);
	}
}

void url_filter_mark_item (UrlFilter* filter, int min_pick_count, int max_pick_count)
{
	GSList* slist;
	UrlItem* uitem;
	int  count;

	for (slist=filter->item_list; slist; slist=slist->next) {
		uitem = slist->data;
		count = uitem->picked_count;
		if (count >= min_pick_count && count <= max_pick_count)
			uitem->mark = TRUE;
	}
}

GSList* url_filter_get_marked_item (UrlFilter* filter, int* n_marked)
{
	GSList* slist;
	GSList* slist_return = NULL;
	GSList* slist_return_tail = NULL;
	UrlItem* uitem;
	int n = 0;

	for (slist=filter->item_list; slist; slist=slist->next) {
		uitem = slist->data;
		if (uitem->mark) {
			slist_return_tail = g_slist_append (slist_return_tail, uitem);
			if (slist_return == NULL)
				slist_return = slist_return_tail;
			else
				slist_return_tail = slist_return_tail->next;
			n++;
		}
	}
	if (n_marked)
		*n_marked = n;
	return slist_return;
}

void url_filter_pick_by_marked_class (UrlFilter* filter)
{
	GSList* slist;
	UrlFilterClass* fclass;

	for (slist=filter->class_list; slist; slist=slist->next) {
		fclass = slist->data;
		url_filter_class_pick_marked_item (fclass);
	}
}

// UrlFilterClass ----------------------------------------------------

void url_filter_class_finalize (UrlFilterClass* fclass)
{
	g_hash_table_destroy (fclass->hash_table);
	url_item_list_instance_finalize (URL_ITEM_LIST (fclass));
	g_message ("UrlFilterClass free");
}

UrlFilterClass* url_filter_class_new (UrlFilterClassFunc fn)
{
	UrlFilterClass* fclass;

	fclass = g_malloc0 (sizeof (UrlFilterClass));

	// initialize base class
	url_item_list_instance_init (URL_ITEM_LIST (fclass));
	fclass->finalize = (UrlItemListFinalizeFunc)url_filter_class_finalize;

	fclass->class_func = fn;
	fclass->hash_table = g_hash_table_new (g_str_hash, g_str_equal);
	return fclass;
}

void url_filter_class_pick_marked_item (UrlFilterClass* fclass)
{
	UrlItem* class_uitem;
	GSList* slist;

	for (slist=fclass->item_list; slist; slist=slist->next) {
		class_uitem = slist->data;
		if (class_uitem->mark) {
			url_item_pick_related_item (class_uitem);
		}
	}
}

void url_filter_class_string (UrlFilterClass* fclass, UrlItem* uitem, char* string)
{
	UrlItem* class_uitem;

	class_uitem = g_hash_table_lookup (fclass->hash_table, (string) ? string : "");
	if (class_uitem == NULL) {
		class_uitem = url_item_new (string, -1);
		g_hash_table_insert (fclass->hash_table, class_uitem->string, class_uitem);
		url_filter_class_add (fclass, class_uitem);
	}
	url_item_add_related (class_uitem, uitem);
}

void url_filter_class_protocol (UrlFilterClass* fclass, UrlItem* uitem, UrlInfo* uinfo)
{
	gchar*  sub_string;

	sub_string = g_strndup (uinfo->protocol, uinfo->protocol_len);
	url_filter_class_string (fclass, uitem, sub_string);
	g_free (sub_string);
}

void url_filter_class_address (UrlFilterClass* fclass, UrlItem* uitem, UrlInfo* uinfo)
{
	gchar*  sub_string;

	sub_string = g_strndup (uinfo->address, uinfo->address_len);
	url_filter_class_string (fclass, uitem, sub_string);
	g_free (sub_string);
}

void url_filter_class_extension (UrlFilterClass* fclass, UrlItem* uitem, UrlInfo* uinfo)
{
	gchar*  sub_string;

	sub_string = g_strndup (uinfo->ext_filename, uinfo->ext_filename_len);
	url_filter_class_string (fclass, uitem, sub_string);
	g_free (sub_string);
}

